package com.zhiyin.game.Service;

import com.zhiyin.game.bean.Cell;

import com.zhiyin.game.bean.Vector2;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
public class RoleService {

    private int DISTANCE = 5;

    /**
     * 填充小偷和警察的数据
     *
     * @param cells
     * @return
     */
    public Map initRoleData(Cell[][] cells) {
        Map resultMap = new HashMap();
        List<Vector2> bankPosList = getBankPos(cells);
        System.out.println(bankPosList);
        Map<String, List<Vector2>> bankAroundPos = getBankAroundPos(cells, bankPosList);
        System.out.println(bankAroundPos);
        resultMap.putAll(findRolePos(cells, bankPosList, bankAroundPos));
        return resultMap;
    }

    private Map<String, Vector2> findRolePos(Cell[][] map, List<Vector2> bankPosList, Map<String, List<Vector2>> bankAroundPos) {
        Map result = new HashMap();
        Random random = new Random();
        Vector2 pos0 = null;
        Vector2 pos1 = null;
        int i=0;
        do{
            List<String> vector2s = new ArrayList<>(bankAroundPos.keySet());
            String pos = vector2s.get(random.nextInt(vector2s.size()));
            int size = bankAroundPos.get(pos).size();
            if(size>=2){
                Set<Integer> randomSet = new HashSet<>();
                while (randomSet.size()<2){
                    randomSet.add(random.nextInt(size));
                }
                List<Integer> indexs = new ArrayList<>(randomSet);
                pos0 = bankAroundPos.get(pos).get(indexs.get(0));
                pos1 = bankAroundPos.get(pos).get(indexs.get(1));
                if(Math.abs(pos0.getX()-pos1.getX())+Math.abs(pos0.getY()-pos1.getY())>3){
                    result.put("thief", createVector2(pos0.getX(),pos0.getY()));
                    result.put("police", createVector2(pos1.getX(),pos1.getY()));
                    break;
                }
            }
            i++;
        }while (i<100);
        if(i == 100){
            result.put("thief", createVector2(pos0.getX(), pos0.getY()));
            result.put("police", createVector2(pos1.getX(), pos1.getY()));
        }
        System.out.println("i:"+i);
        System.out.println(result);
        return result;
    }

    private Map<String, List<Vector2>> getBankAroundPos(Cell[][] map, List<Vector2> bankPosList) {
        Set<Vector2> openList = new HashSet<>();
        Map<String, List<Vector2>> resultList = new HashMap<>();
        Set<Vector2> nextList = null;
        openList.addAll(bankPosList);
        int step = 0;
        do{
            nextList = new HashSet<>();
            for(Vector2 pos : openList){
                if(getCell(map, pos.getX(), pos.getY()).getStep() != step){
                    continue;
                }
                int posX = pos.getX();
                int posY = pos.getY();
                int width = map[0].length;
                int height = map.length;
                getCell(map, posX, posY).setVisited(true);
                List<String> moveDir = new ArrayList<>();

                if (posX > 0 && !getCell(map, posX - 1, posY).isVisited() && !getCell(map, posX, posY).isLeftWall())
                    moveDir.add("L");
                if (posX < width - 1 && !getCell(map, posX + 1, posY).isVisited() && !getCell(map, posX, posY).isRightWall())
                    moveDir.add("R");
                if (posY < height - 1 && !getCell(map, posX, posY + 1).isVisited() && !getCell(map, posX, posY).isBottomWall())
                    moveDir.add("D");
                if (posY > 0 && !getCell(map, posX, posY - 1).isVisited() && !getCell(map, posX, posY).isTopWall())
                    moveDir.add("U");

                if (posX > 0 && getCell(map, posX - 1, posY).getStep()<getCell(map, posX, posY).getStep() && !getCell(map, posX, posY).isLeftWall()){
                    getCell(map, posX - 1, posY).setStep(0);
                }
                if (posX < width - 1 && getCell(map, posX + 1, posY).getStep()<getCell(map, posX, posY).getStep() && !getCell(map, posX, posY).isRightWall()){
                    getCell(map, posX + 1, posY).setStep(0);
                }
                if (posY < height - 1 && getCell(map, posX, posY + 1).getStep()<getCell(map, posX, posY).getStep() && !getCell(map, posX, posY).isBottomWall()) {
                    getCell(map, posX, posY + 1).setStep(0);
                }
                if (posY > 0 && getCell(map, posX, posY - 1).getStep()<getCell(map, posX, posY).getStep() && !getCell(map, posX, posY).isTopWall()){
                    getCell(map, posX, posY - 1).setStep(0);
                }


                if (moveDir.size() > 0) {
                    String dir = "";
                    for(int i=0;i<moveDir.size();i++){
                        dir = moveDir.get(i);
                        Vector2 nextPos = null;
                        switch (dir) {
                            case "L":
                                nextPos = new Vector2(posX-1,posY);
                                break;
                            case "R":
                                nextPos = new Vector2(posX+1,posY);
                                break;
                            case "D":
                                nextPos = new Vector2(posX,posY+1);
                                break;
                            case "U":
                                nextPos = new Vector2(posX,posY-1);
                                break;
                        }
                        if(getCell(map, posX, posY).getStep() < DISTANCE){
                            getCell(map, nextPos.getX(), nextPos.getY()).setStep(getCell(map, posX, posY).getStep()+1);
                            if(getCell(map, posX, posY).getParentPos()==null){
                                getCell(map, nextPos.getX(), nextPos.getY()).setParentPos(new Vector2(posX, posY));
                            }else{
                                getCell(map, nextPos.getX(), nextPos.getY()).setParentPos(getCell(map, posX, posY).getParentPos());
                            }
                            nextList.add(nextPos);
                        }
                    }
                }
            }
            step++;
            openList = nextList;
        }while (nextList.size()>0);

        for(int i=0;i<map[0].length;i++){
            for(int j=0;j<map.length;j++){
                if(getCell(map, i,j).getStep()==DISTANCE){
                    Vector2 parentPos = getCell(map, i, j).getParentPos();
                    String parentPosStr = parentPos.getX() + "," + parentPos.getY();
                    Vector2 vec = new Vector2(i, j);
                    if(resultList.containsKey(parentPosStr)){
                        List<Vector2> list = resultList.get(parentPosStr);
                        list.add(vec);
                        resultList.put(parentPosStr, list);
                    }else{
                        List<Vector2> list = new ArrayList<>();
                        list.add(vec);
                        resultList.put(parentPosStr, list);
                    }
                }
            }
        }
        return resultList;
    }

    private Cell getCell(Cell[][] map, int x, int y) {
        return map[x][y];
    }

    private Vector2 createVector2(int x, int y){
        return new Vector2(y,x);
    }
    /**
     * 获取地图中银行的位置坐标
     * @param cells
     * @return
     */
    private List<Vector2> getBankPos(Cell[][] cells){
        List<Vector2> result = new ArrayList<>();
        for(int i=0;i<cells.length;i++){
            for(int j=0;j<cells[i].length;j++){
                if(cells[i][j].getMark()>0){
                    result.add(new Vector2(i,j));
                }
                //初始化所有格子都没有被访问
                cells[i][j].setVisited(false);
            }
        }
        return result;
    }


    public Map<String, Integer> getThief(Cell[][] cells) {
        Map<String, Integer> thief = new HashMap<>();
        int x = (int) (Math.random() * 10);
        int y = (int) (Math.random() * 10);
        Cell cells1 = cells[x][y];
        if (cells1.getMark() <= 0) {
            thief.put("x", x);
            thief.put("y", y);
            return thief;
        } else {
            return getThief(cells);
        }
    }

    public Map<String, Integer> getPolice(Cell[][] cells) {
        Map<String, Integer> police = new HashMap<>();
        int x = (int) (Math.random() * 10);
        int y = (int) (Math.random() * 10);
        Cell cells1 = cells[x][y];
        if (cells1.getMark() <= 0) {
            police.put("x", x);
            police.put("y", y);
            return police;
        } else {
            return getPolice(cells);
        }
    }

}
